﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Avivo.Common;
using Avivo.Models;
using Dokan;
using Microsoft.SmartDevice.Connectivity;

namespace Avivo
{
	public class IsolatedStorageOperations : DokanOperations
	{
		#region Private members
		private const string ROOT_FOLDER = "\\";

		private uint lastSysinfoJsonSize;
		private uint lastSysinfoXmlSize;
		private uint lastReadmeTxtSize;
		private Device device;

		private List<SyncFile> sync;
		#endregion

		#region Constructor
		public IsolatedStorageOperations(Device device)
		{
			this.device = device;
			this.sync = new List<SyncFile>();
		}
		#endregion

		#region Protected methods
		protected string GetIsolatedStorageFileName(string path)
		{
			//"Shared\Music\sample.mp3" => "sample.mp3"
			string name = GetIsolatedStorageFilePath(path);
			int index = name.LastIndexOf("\\");
			name = (index >= 0 ? name.Substring(index + 1) : name);
			return name;
		}

		protected string GetIsolatedStorageFilePath(string path)
		{
			//"\Applications\Data\815816ac-d0db-4b52-8661-7b81e3c8e89e\Data\IsolatedStore\\Shared\Music\sample.mp3" => "Shared\Music\sample.mp3"
			var m = Regex.Match(path, @"\\Applications\\Data\\[\w\d\-]+\\Data\\IsolatedStore\\(\\)?(?<name>.+)");
			if (m.Success)
			{
				path = m.Groups["name"].Value;
			}
			return path;
		}

		protected DeviceInfo GetSystemInfo()
		{
			var sysinfo = device.GetSystemInfo();

			var model = new DeviceInfo();
			model.DeviceId = device.Id.ToString();
			model.DeviceName = device.Name;
			model.DevicePlatform = device.Platform.Name;
			model.AvailablePhysicalSpace = sysinfo.AvailPhys;
			model.TotalPhysicalSpace = sysinfo.TotalPhys;
			model.BatteryLifePercent = (double)sysinfo.BatteryLifePercent / 100;
			model.BatteryLifetime = (sysinfo.BatteryLifetime < 0 ? null : (int?)sysinfo.BatteryLifetime);
			model.CurrentTime = sysinfo.CurrentTime;
			model.Version = string.Format("{0}.{1}.{2}", sysinfo.OSMajor, sysinfo.OSMinor, sysinfo.OSBuildNo);
			model.ACLineStatus = (int)sysinfo.ACLineStatus;

			//List installed applications
			//NOTE: This is useless if cannot retrieve title
			//model.AppList = new List<DeviceInfoApplication>();
			//var apps = device.GetInstalledApplications();
			//foreach (var app in apps)
			//{
			//  var item = new DeviceInfoApplication();
			//  item.ProductId = app.ProductID.ToString();
			//  item.InstanceId = app.InstanceID.ToString();
			//  try
			//  {
			//    item.Title = app.Title;
			//    item.Genre = app.Genre;
			//    item.IsRunning = app.IsRunning();
			//  }
			//  catch
			//  {
			//    //May throw exception on Title or IsRunning()
			//  }
			//  model.AppList.Add(item);
			//}

			return model;
		}

		protected uint ReadString(string text, ref byte[] buffer)
		{
			byte[] data = Encoding.UTF8.GetBytes(text);

			uint length = 0;
			for (int i = 0; i < data.Length && i < buffer.Length; i++)
			{
				buffer[i] = data[i];
				length++;
			}
			return length;
		}
		#endregion

		#region DokanOperations members
		public int Cleanup(string filename, DokanFileInfo info)
		{
			return DokanNet.DOKAN_SUCCESS;
		}

		public int CloseFile(string filename, DokanFileInfo info)
		{
			//Temporary file for read/write I/O
			var file = sync.FirstOrDefault(x => x.Filename == filename);
			if (file != null)
			{
				//When in "write" send the file back to device
				switch (file.Access)
				{
					case FileAccess.Write:
					case FileAccess.ReadWrite:
						var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
						if (match.Success)
						{
							string guid = match.Groups["guid"].Value;
							string path = match.Groups["path"].Value;

							var app = device.GetApplication(new Guid(guid));
							var store = app.GetIsolatedStore();

							store.SendFile(file.TempPath, file.ISPath, true);
						}
						break;
				}

				//File is no longer used when closed
				string temp = file.TempPath;
				sync.Remove(file);

				if (File.Exists(temp))
				{
					File.Delete(temp);
				}
			}

			return DokanNet.DOKAN_SUCCESS;
		}

		public int CreateDirectory(string filename, DokanFileInfo info)
		{
			//Create directory in Isolated Storage
			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;
				string path = match.Groups["path"].Value;

				var app = device.GetApplication(new Guid(guid));
				var store = app.GetIsolatedStore();

				if (store.DirectoryExists(path))
				{
					return -DokanNet.ERROR_ALREADY_EXISTS;
				}
				store.CreateDirectory(path);

				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_ACCESS_DENIED;
		}

		public int CreateFile(string filename, FileAccess access, FileShare share, FileMode mode, FileOptions options, DokanFileInfo info)
		{
			if (!info.IsDirectory) //Not reliable?
			{
				//Example: \apps\{guid}\sample.txt
				var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
				if (match.Success)
				{
					string guid = match.Groups["guid"].Value;
					string path = match.Groups["path"].Value;

					//Temporary file for read/write I/O
					var file = sync.FirstOrDefault(x => x.Filename == filename);
					if (file == null)
					{
						string temp = Path.GetTempFileName();

						var app = device.GetApplication(new Guid(guid));
						var store = app.GetIsolatedStore();

						//Determine what to do
						switch (mode)
						{
							case FileMode.Create:
								break;

							case FileMode.Append:
							case FileMode.OpenOrCreate:
								if (store.FileExists(path))
								{
									store.ReceiveFile(path, temp, true);
								}
								break;

							case FileMode.CreateNew:
								if (store.FileExists(path))
								{
									return -DokanNet.ERROR_FILE_EXISTS;
								}
								break;

							case FileMode.Open:
								if (!store.FileExists(path))
								{
									return -DokanNet.ERROR_FILE_NOT_FOUND;
								}

								store.ReceiveFile(path, temp, true);
								break;

							case FileMode.Truncate:
								return -DokanNet.DOKAN_ERROR; //Not implemented
						}

						//Create empty file for writing
						if (!File.Exists(temp))
						{
							File.Create(temp);
						}

						//Register file action
						sync.Add(new SyncFile()
						{
							Filename = filename,
							ISPath = path,
							TempPath = temp,
							Access = access,
							Mode = mode,
						});
					}

					return DokanNet.DOKAN_SUCCESS;
				}

				//Install an application
				//Example: \install\my-app.xap
				match = Regex.Match(filename, @"^\\install\\(?<name>[\w\d\-_]+)\.xap$", RegexOptions.IgnoreCase);
				if (match.Success)
				{
					string name = match.Groups["name"].Value;
					var guid = Guid.NewGuid();

					try
					{
						//If name is actually GUID
						guid = new Guid(name);

						//Check if application is already installed
						if (device.IsApplicationInstalled(guid))
						{
							return -DokanNet.ERROR_ALREADY_EXISTS;
						}
					}
					catch
					{
					}

					try
					{
						name = guid.ToString("N");

#if !DEBUG
						throw new NotImplementedException();
#endif

						//MSDN: http://msdn.microsoft.com/en-us/library/microsoft.smartdevice.connectivity.device.getfiledeployer%28v=vs.90%29.aspx
						var deployer = device.GetFileDeployer();
						deployer.SendFile(@"d:\temp\demo.xap", name + ".xap"); //Throws exception: 0x8973190E

						var app = device.InstallApplication(guid, guid, "Application", null, name + ".xap");
						app.Launch(); //Launch after install
					}
					catch
					{
						return -DokanNet.DOKAN_ERROR;
					}

					return DokanNet.DOKAN_SUCCESS;
				}
			}

			return DokanNet.DOKAN_SUCCESS;
			//return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int DeleteDirectory(string filename, DokanFileInfo info)
		{
			//Root directory cannot be deleted
			if (filename == ROOT_FOLDER)
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//Reserved directories cannot be deleted
			if (Regex.IsMatch(filename, @"^\\(apps|install)(\\)?$"))
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//Delete directory from Isolated Storage
			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;
				string path = match.Groups["path"].Value;

				var app = device.GetApplication(new Guid(guid));
				var store = app.GetIsolatedStore();

				if (!store.DirectoryExists(path))
				{
					return -DokanNet.ERROR_PATH_NOT_FOUND;
				}
				store.DeleteDirectory(path);

				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int DeleteFile(string filename, DokanFileInfo info)
		{
			//"sysinfo.json" contains current device information in JSON format
			if (filename == ROOT_FOLDER + "sysinfo.json")
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//"sysinfo.xml" contains current device information in XML format
			if (filename == ROOT_FOLDER + "sysinfo.xml")
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//"readme.txt" contains info how to use the virtual drive
			if (filename == ROOT_FOLDER + "readme.txt")
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//Delete file from Isolated Storage
			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;
				string path = match.Groups["path"].Value;

				string temp = Path.GetTempFileName();

				var app = device.GetApplication(new Guid(guid));
				var store = app.GetIsolatedStore();

				if (!store.FileExists(path))
				{
					return -DokanNet.ERROR_FILE_NOT_FOUND;
				}
				store.DeleteFile(path);

				return DokanNet.DOKAN_SUCCESS;
			}

			//Uninstall an application
			match = Regex.Match(filename, @"^\\install\\(?<guid>[\w\d\-]+)\.xap$", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;

				var app = device.GetApplication(new Guid(guid));
				app.Uninstall();

				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_FILE_NOT_FOUND;
		}

		public int FlushFileBuffers(string filename, DokanFileInfo info)
		{
			return DokanNet.DOKAN_SUCCESS;
		}

		public int FindFiles(string filename, ArrayList files, DokanFileInfo info)
		{
			var time = DateTime.Now;

			if (filename == ROOT_FOLDER)
			{
				//"apps" folder contains list of applications and isolated storage content for each one
				var apps = new FileInformation();
				apps.FileName = "apps";
				apps.Attributes = FileAttributes.Directory;
				apps.LastAccessTime = time;
				apps.LastWriteTime = time;
				apps.CreationTime = time;
				files.Add(apps);

				//"install" folder contains list of installed applications; user can install new or uninstall existing
				var install = new FileInformation();
				install.FileName = "install";
				install.Attributes = FileAttributes.Directory;
				install.LastAccessTime = time;
				install.LastWriteTime = time;
				install.CreationTime = time;
				files.Add(install);

				//"readme.txt" contains info how to use the virtual drive
				var readme = new FileInformation();
				readme.FileName = "readme.txt";
				readme.Attributes = FileAttributes.Normal;
				readme.LastAccessTime = time;
				readme.LastWriteTime = time;
				readme.CreationTime = time;
				files.Add(readme);

				//"sysinfo.json" contains current device information in JSON format
				var json = new FileInformation();
				json.FileName = "sysinfo.json";
				json.Attributes = FileAttributes.Normal;
				json.LastAccessTime = time;
				json.LastWriteTime = time;
				json.CreationTime = time;
				files.Add(json);

				//"sysinfo.xml" contains current device information in XML format
				var xml = new FileInformation();
				xml.FileName = "sysinfo.xml";
				xml.Attributes = FileAttributes.Normal;
				xml.LastAccessTime = time;
				xml.LastWriteTime = time;
				xml.CreationTime = time;
				files.Add(xml);

				return DokanNet.DOKAN_SUCCESS;
			}

			if (filename == ROOT_FOLDER + "apps")
			{
				//List applications in the "apps" folder
				var apps = device.GetInstalledApplications();
				foreach (var app in apps)
				{
					var file = new FileInformation();
					file.FileName = app.ProductID.ToString();
					file.Attributes = FileAttributes.Directory;
					file.LastAccessTime = time;
					file.LastWriteTime = time;
					file.CreationTime = time;
					files.Add(file);
				}

				return DokanNet.DOKAN_SUCCESS;
			}

			if (filename == ROOT_FOLDER + "install")
			{
				//List applications in the "install" folder
				var apps = device.GetInstalledApplications();
				foreach (var app in apps)
				{
					var file = new FileInformation();
					file.FileName = app.ProductID.ToString() + ".xap";
					file.Attributes = FileAttributes.Normal;
					file.LastAccessTime = time;
					file.LastWriteTime = time;
					file.CreationTime = time;
					files.Add(file);
				}

				return DokanNet.DOKAN_SUCCESS;
			}

			if (filename.StartsWith(ROOT_FOLDER + "apps" + "\\"))
			{
				var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))?", RegexOptions.IgnoreCase);
				if (match.Success)
				{
					string guid = match.Groups["guid"].Value;
					string path = match.Groups["path"].Value;

					var app = device.GetApplication(new Guid(guid));
					var store = app.GetIsolatedStore();
					var list = store.GetDirectoryListing(path);
					foreach (var item in list)
					{
						var file = new FileInformation();
						file.FileName = GetIsolatedStorageFileName(item.Name);
						file.Attributes = item.FileAttribute;
						file.LastAccessTime = item.LastAccessTime;
						file.LastWriteTime = item.LastWriteTime;
						file.CreationTime = item.CreationTime;
						file.Length = item.Length;
						files.Add(file);
					}

					return DokanNet.DOKAN_SUCCESS;
				}
			}

			return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int GetFileInformation(string filename, FileInformation fileinfo, DokanFileInfo info)
		{
			//"sysinfo.json" contains current device information in JSON format
			if (filename == ROOT_FOLDER + "sysinfo.json")
			{
				var time = DateTime.Now;
				fileinfo.FileName = "sysinfo.json";
				fileinfo.Attributes = FileAttributes.Normal;
				fileinfo.LastAccessTime = time;
				fileinfo.LastWriteTime = time;
				fileinfo.CreationTime = time;
				fileinfo.Length = this.lastSysinfoJsonSize;
				return DokanNet.DOKAN_SUCCESS;
			}

			//"sysinfo.xml" contains current device information in XML format
			if (filename == ROOT_FOLDER + "sysinfo.xml")
			{
				var time = DateTime.Now;
				fileinfo.FileName = "sysinfo.xml";
				fileinfo.Attributes = FileAttributes.Normal;
				fileinfo.LastAccessTime = time;
				fileinfo.LastWriteTime = time;
				fileinfo.CreationTime = time;
				fileinfo.Length = this.lastSysinfoXmlSize;
				return DokanNet.DOKAN_SUCCESS;
			}

			//"readme.txt" contains info how to use the virtual drive
			if (filename == ROOT_FOLDER + "readme.txt")
			{
				var time = DateTime.Now;
				fileinfo.FileName = "readme.txt";
				fileinfo.Attributes = FileAttributes.Normal;
				fileinfo.LastAccessTime = time;
				fileinfo.LastWriteTime = time;
				fileinfo.CreationTime = time;
				fileinfo.Length = this.lastReadmeTxtSize;
				return DokanNet.DOKAN_SUCCESS;
			}

			//A file inside Isolated Storage
			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;
				string path = match.Groups["path"].Value;

				//Get Isolated Storage for the specific application
				var app = device.GetApplication(new Guid(guid));
				var store = app.GetIsolatedStore();

				//Get file info by listing files from directory
				string directory = Path.GetDirectoryName(path);
				var files = store.GetDirectoryListing(directory);
				foreach (var file in files)
				{
					string local = GetIsolatedStorageFilePath(file.Name);
					if (local == path)
					{
						fileinfo.FileName = Path.GetFileName(path);
						fileinfo.Attributes = FileAttributes.Normal;
						fileinfo.LastAccessTime = file.LastAccessTime;
						fileinfo.LastWriteTime = file.LastWriteTime;
						fileinfo.CreationTime = file.CreationTime;
						fileinfo.Length = file.Length;
						return DokanNet.DOKAN_SUCCESS;
					}
				}
			}

			//Installed applications inside "install" directory
			match = Regex.Match(filename, @"^\\install\\(?<guid>[\w\d\-]+)\.xap$", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				var time = DateTime.Now;
				string guid = match.Groups["guid"].Value;
				var app = device.GetApplication(new Guid(guid));
				fileinfo.FileName = guid + ".xap";
				fileinfo.Attributes = FileAttributes.Normal;
				fileinfo.LastAccessTime = time;
				fileinfo.LastWriteTime = time;
				fileinfo.CreationTime = time;
				//fileinfo.Length = ;
				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_FILE_NOT_FOUND;
		}

		public int LockFile(string filename, long offset, long length, DokanFileInfo info)
		{
			return DokanNet.DOKAN_SUCCESS;
		}

		public int MoveFile(string filename, string newname, bool replace, DokanFileInfo info)
		{
			return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int OpenDirectory(string filename, DokanFileInfo info)
		{
			if (filename == ROOT_FOLDER)
			{
				return DokanNet.DOKAN_SUCCESS;
			}

			if (Regex.IsMatch(filename, @"^\\(apps|install)(\\)?$"))
			{
				return DokanNet.DOKAN_SUCCESS;
			}

			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))?", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				//TODO: Check guid and path
				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_FILE_NOT_FOUND;
		}

		public int ReadFile(string filename, byte[] buffer, ref uint readBytes, long offset, DokanFileInfo info)
		{
			//"sysinfo.json" contains current device information in JSON format
			if (filename == ROOT_FOLDER + "sysinfo.json")
			{
				if (offset != 0)
				{
					return -DokanNet.DOKAN_ERROR;
				}

				var model = GetSystemInfo();
				string json = Helper.JsonSerialize(model);
				byte[] data = Encoding.UTF8.GetBytes(json);
				this.lastSysinfoJsonSize = readBytes = ReadString(json, ref buffer);
				return DokanNet.DOKAN_SUCCESS;
			}

			//"sysinfo.xml" contains current device information in XML format
			if (filename == ROOT_FOLDER + "sysinfo.xml")
			{
				if (offset != 0)
				{
					return -DokanNet.DOKAN_ERROR;
				}

				var model = GetSystemInfo();
				string xml = Helper.XmlSerialize(model);

				//Beautify XML code
				xml = xml.Replace(" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"", " ");
				xml = XDocument.Parse(xml).ToString();

				this.lastSysinfoXmlSize = readBytes = ReadString(xml, ref buffer);
				return DokanNet.DOKAN_SUCCESS;
			}

			//"readme.txt" contains info how to use the virtual drive
			if (filename == ROOT_FOLDER + "readme.txt")
			{
				if (offset != 0)
				{
					return -DokanNet.DOKAN_ERROR;
				}

				string text = ResourceHelper.GetString("Resources/readme.txt");
				this.lastReadmeTxtSize = readBytes = ReadString(text, ref buffer);
				return DokanNet.DOKAN_SUCCESS;
			}

			//Read a file from Isolated Storage
			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;
				string path = match.Groups["path"].Value;

				//Temporary file for read/write I/O
				var file = sync.FirstOrDefault(x => x.Filename == filename);
				if (file == null)
				{
					//File not opened
					return -DokanNet.DOKAN_ERROR;
				}

				string temp = file.TempPath;
				using (var stream = File.OpenRead(temp))
				{
					stream.Position = (int)offset;
					readBytes = (uint)stream.Read(buffer, 0, buffer.Length);
				}

				return DokanNet.DOKAN_SUCCESS;
			}

			//Installed application
			match = Regex.Match(filename, @"^\\install\\(?<guid>[\w\d\-]+)\.xap$", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;

				//Check if exists
				var app = device.GetApplication(new Guid(guid));

				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_FILE_NOT_FOUND;
		}

		public int WriteFile(string filename, byte[] buffer, ref uint writtenBytes, long offset, DokanFileInfo info)
		{
			//"sysinfo.json" contains current device information in JSON format
			if (filename == ROOT_FOLDER + "sysinfo.json")
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//"sysinfo.xml" contains current device information in XML format
			if (filename == ROOT_FOLDER + "sysinfo.xml")
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//"readme.txt" contains info how to use the virtual drive
			if (filename == ROOT_FOLDER + "readme.txt")
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//Installed applications inside "install" directory
			if (Regex.IsMatch(filename, @"^\\install\\(?<guid>[\w\d\-]+)\.xap$", RegexOptions.IgnoreCase))
			{
				return -DokanNet.ERROR_ACCESS_DENIED;
			}

			//Write a file to Isolated Storage
			var match = Regex.Match(filename, @"^\\apps\\(?<guid>[\w\d\-]+)(\\(?<path>.+))", RegexOptions.IgnoreCase);
			if (match.Success)
			{
				string guid = match.Groups["guid"].Value;
				string path = match.Groups["path"].Value;

				//Temporary file for read/write I/O
				var file = sync.FirstOrDefault(x => x.Filename == filename);
				if (file == null)
				{
					//File not opened
					return -DokanNet.DOKAN_ERROR;
				}

				string temp = file.TempPath;
				using (var stream = File.OpenWrite(temp))
				{
					stream.Position = (int)offset;
					stream.Write(buffer, 0, buffer.Length);
					writtenBytes = (uint)buffer.Length;
				}

				return DokanNet.DOKAN_SUCCESS;
			}

			return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int SetEndOfFile(string filename, long length, DokanFileInfo info)
		{
			return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int SetAllocationSize(string filename, long length, DokanFileInfo info)
		{
			return -DokanNet.ERROR_PATH_NOT_FOUND;
		}

		public int SetFileAttributes(string filename, FileAttributes attr, DokanFileInfo info)
		{
			return -DokanNet.DOKAN_ERROR;
		}

		public int SetFileTime(string filename, DateTime ctime, DateTime atime, DateTime mtime, DokanFileInfo info)
		{
			return -DokanNet.DOKAN_ERROR;
		}

		public int UnlockFile(string filename, long offset, long length, DokanFileInfo info)
		{
			return DokanNet.DOKAN_SUCCESS;
		}

		public int Unmount(DokanFileInfo info)
		{
			return DokanNet.DOKAN_SUCCESS;
		}

		public int GetDiskFreeSpace(ref ulong freeBytesAvailable, ref ulong totalBytes, ref ulong totalFreeBytes, DokanFileInfo info)
		{
			var sysinfo = device.GetSystemInfo();
			freeBytesAvailable = (ulong)sysinfo.AvailPhys;
			totalBytes = (ulong)sysinfo.TotalPhys;
			totalFreeBytes = int.MaxValue; //Reserved value
			return DokanNet.DOKAN_SUCCESS;
		}
		#endregion
	}
}
